package org.mte.sak.util;

import java.util.ArrayList;
import java.util.Iterator;


/**
 * StripBuilder: 
 * costruisce una ArrayList di interi  visualizzando gli interi 
 * vicino al un intero dato e approssimando la visualizzazione 
 * verso il min e verso il max degli insieme degli interi
 * 
 * Ad esempio si ha
 * min = 1 è il valore minimo dell'insieme
 * max = 20 è il valore massimo dell'insieme
 * cp =  12 è l'intero di riferimento
 * step = 2 è numero di interi a destra e a sinistra di cp 
 * 
 * allora il risultato sarà una ArrayList di interi cosi formato:
 * 
 * 1, -1, 10, 11, 12, 13, 14, -1, 20
 * 
 * dove l'intero -1 indica l'approssimazione.
 * 
 * Si deve considerare anche che il ArrayList restituito
 * è corretto ad avere sempre la stessa lunghezza in funzione
 * dello step dato secondo
 * 
 * len = step * 2 + 5;
 * 
 * ossia l'insieme dei numeri restituito è dato da:
 * 
 * -min
 * -approssimazione sinistra (-1)
 * -interi step sinistro
 * -intero di riferimento
 * -interi step destro
 * -approssimazione destra (-1)
 * -max
 * 
 * Quando l'intero di riferimento si avvicina al valore min o al valore max
 * avviene la correzione perché lo step e l'approssimazione destra o sinistra 
 * si riducono o si eliminano, quindi si aumenta la numerosita dello step contrario
 * 
 * Ad esempio si a
 *  
 *  min = 1
 *  max = 20
 *  cp = 18
 *  step = 2
 * 
 *  La correzione ha aumentato lo step sinistro di 14 e 15 per compensare quello destro
 *  1, -1, 14, 15, 16, 17, 18, 19, 20, 
 *
 * @author Marco Traversari
 * @version $Revision: 1.1 $ $Date: 2012-03-23 15:30:39 $ $Author: marco $
 */
public class StripBuilder {
	
	/**
	 * build
	 * @param min numero minimo
	 * @param max numero massimo
	 * @param cp numero corrente
	 * @param step quanti numeri sono visibili a destra e a sinistra del numero corrente
	 * @return tokens
	 */
    public static ArrayList<Integer> build(int min, int max, int cp, int step) {
		ArrayList<Integer> tokens = new ArrayList<Integer>();
		int lb = cp - step;
		int rb = cp + step;
		lb = (lb < min) ? min : lb;
		rb = (rb > max) ? max : rb;
		if (lb - min > 1) {
			/*
			 * Per indicare di abbreviare a sinistra
			 */
			tokens.add(min);
			if (lb - min == 2) {
				tokens.add(min + 1);
			} else {
				tokens.add(-1);
			}
		}
		if (lb - min == 1) {
			/*
			 * La distanza da min
			 * è uguale a 1 non
			 * c'è abbreviazione
			 */
			tokens.add(min);
		}
		for (int i = lb; i < rb + 1; i++) {
			tokens.add(i);
		}
		if (rb - max < -1) {
			/*
			 * Per indicare di abbreviare a destra
			 */
			if (rb - max == -2) {
				tokens.add(max - 1);
			} else {
				tokens.add(-1);
			}
			tokens.add(max);
		}
		if (rb - max == -1) {
			/*
			 * La distanza da max
			 * è uguale a 1 non
			 * c'è abbreviazione
			 */
			tokens.add(max);
		}
		tokens = correctSize(tokens, min, max, step);
		return tokens;
    }
    
    private static ArrayList<Integer> correctSize(ArrayList<Integer> tokens, int min, int max, int step) {
    	ArrayList<Integer> newtks = null;  
    	int len = step * 2 + 5;
		int size = tokens.size();
    	if (len < max && size < len) {
    		newtks = new ArrayList<Integer>();
    		int correction = len - size;
    		/*
    		 * determina se -1 sta vicino al min o vicino al max
    		 */
    		Iterator<Integer> iterator = tokens.iterator();
    		boolean isMin = false;
    		boolean isMax = false;
    		int i = -1;
    		while (iterator.hasNext() && !isMin && !isMax) {
    			i++;
    			int tk = iterator.next();
    			if (tk == -1) {
	    			int ptk = -1;
	    			int ftk = -1;
	    			if (i >= 1) {
	    				ptk = tokens.get(i - 1);
	    			}
	    			if (i <= size - 1) {
	    				ftk = tokens.get(i + 1);
	    			}
	    			if (ptk == min) {
	    				isMin = true;
	    			} else if (ftk == max ){
	    				isMax = true;
	    			}
    			}
    			
    		}
    		
    		
    		/* Correzione se isMin = true */
    		if (isMin) {
    			int mintk = tokens.get(0);
    			int lasttk = tokens.get(i + 1);
    			
    			newtks.add(mintk);
    			newtks.add(-1);
   			 	for (int c = correction; c > 0; c--) {
					int newtk = lasttk - c;
					newtks.add(newtk);
				}    			
    			for (int o = i + 1; o < size; o++) {
    				newtks.add(tokens.get(o));
    			}
    		}
    		/* */

    		/* Correzione se isMax = true */
    		if (isMax) {
    			int maxtk = tokens.get(size - 1);
				int lasttk = -1;
				for (int l = 0; l < i; l++) {
					lasttk = tokens.get(l);
					//System.out.println("lasttk=" + lasttk);
					newtks.add(lasttk);
				}
				for (int c = 1; c < correction + 1; c++) {
					int newtk = lasttk + c;
					newtks.add(newtk);
				}
    			newtks.add(-1);
    			newtks.add(maxtk);
    		}
    		/* */

    	} else {
    		/* non c'è bisogno di correzione */
    		newtks = tokens;
    	}
    	return newtks;
    }
	
}
